﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;

namespace DrawOnDesktop
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            textBox1.Hide();
            
        }

#region 屏幕最大化
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr GetDesktopWindow();
        [DllImport("user32.dll", EntryPoint = "GetDCEx", CharSet = CharSet.Auto, ExactSpelling = true)]
        private static extern IntPtr GetDCEx(IntPtr hWnd, IntPtr hrgnClip, int flags);

        private void FullScreen()
        {
            IntPtr desk = GetDesktopWindow();
            IntPtr deskDC = GetDCEx(desk, IntPtr.Zero, 0x403);
            Graphics g = Graphics.FromHdc(deskDC);
            //g.DrawString("这是一个测试", new Font("宋体", 50, FontStyle.Bold), Brushes.Red, new PointF(100, 100));
            fullscreen = !fullscreen;//循环。点一次全屏，再点还原。   
            SetFullScreen(fullscreen, ref rect);
            if (fullscreen)
            {
                this.WindowState = FormWindowState.Maximized;//全屏 
                this.ShowInTaskbar = true;
            }
            else
            {
                this.WindowState = FormWindowState.Minimized;//还原   
                this.ShowInTaskbar = false;
                notifyIcon.ShowBalloonTip(1000);
            }
        }
        bool fullscreen = false;
        Rectangle rect = new Rectangle();
        /// <summary>   
        /// 设置全屏或这取消全屏   
        /// </summary>   
        /// <param name="fullscreen">true:全屏 false:恢复</param>   
        /// <param name="rectOld">设置的时候，此参数返回原始尺寸，恢复时用此参数设置恢复</param>   
        /// <returns>设置结果</returns>   
        public static bool SetFullScreen(bool fullscreen, ref Rectangle rectOld)
        {
            int Hwnd = 0;
            Hwnd = FindWindow("Shell_TrayWnd", null);
            if (Hwnd == 0) return false;
            if (fullscreen)
            {
                ShowWindow(Hwnd, SW_HIDE);
                Rectangle rectFull = Screen.PrimaryScreen.Bounds;
                SystemParametersInfo(SPI_GETWORKAREA, 0, ref rectOld, SPIF_UPDATEINIFILE);//get   
                SystemParametersInfo(SPI_SETWORKAREA, 0, ref rectFull, SPIF_UPDATEINIFILE);//set   
            }
            else
            {
                ShowWindow(Hwnd, SW_SHOW);
                SystemParametersInfo(SPI_SETWORKAREA, 0, ref rectOld, SPIF_UPDATEINIFILE);
            }
            return true;
        }
#endregion

#region 获取全局键盘钩子
        [DllImport("user32.dll", EntryPoint = "ShowWindow")]
        public static extern int ShowWindow(int hwnd, int nCmdShow);
        public const int SW_SHOW = 5; public const int SW_HIDE = 0;

        [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
        private static extern int SystemParametersInfo(int uAction, int uParam, ref Rectangle lpvParam, int fuWinIni);
        public const int SPIF_UPDATEINIFILE = 0x1;
        public const int SPI_SETWORKAREA = 47;
        public const int SPI_GETWORKAREA = 48;

        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern int FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall, SetLastError = true)]
         private static extern int SetWindowsHookEx(
            int idHook,
            HookProc lpfn,
            IntPtr hMod,
            int dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto,
                    CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern int UnhookWindowsHookEx(int idHook);

        [DllImport("user32.dll", CharSet = CharSet.Auto,
                     CallingConvention = CallingConvention.StdCall)]
        private static extern int CallNextHookEx(
            int idHook,
            int nCode,
            int wParam,
            IntPtr lParam);
        /// <summary>
        /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
        /// </summary>
        private const int WH_MOUSE_LL = 14;
        /**/
        /// <summary>
        /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.
        /// </summary>
        private const int WH_KEYBOARD_LL = 13;
        int hKeyboardHook;
        delegate int HookProc(int nCode,int wParam,IntPtr lParam);
        [StructLayout(LayoutKind.Sequential)]
        public class KeyboardHookStruct
        {
            public int vkCode;//表达一个在1到254间的虚拟键盘码
            public int scanCode;//表示硬件扫描码
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        private void InitHook()
        {
         
                hKeyboardHook = SetWindowsHookEx(
                   WH_KEYBOARD_LL, //原来是WH_KEYBORAD
                   KeyboardHookProcedure,
                   Marshal.GetHINSTANCE(
                   Assembly.GetExecutingAssembly().GetModules()[0]),
                   0);
           
        }
        private int KeyboardHookProcedure(int nCode, int wParam, IntPtr lParam)
        {
            //it was ok and someone listens to events
            if (nCode >= 0)
            {
                //read structure KeyboardHookStruct at lParam
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                //raise KeyDown
                Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                if ((MyKeyboardHookStruct.flags>>7) ==0)
                {
                    if (keyData == Keys.H && Control.ModifierKeys == Keys.Control && !IsOnDrawing)
                    {
                        RefreshScreenPic();
                        FullScreen();
                    }
                    else if (keyData == Keys.Space && fullscreen && !IsOnDrawing)
                    {
                        DrawingMode = (DrawingMode + 1) % FigureEx.ShapeNum;
                        switch (DrawingMode)
                        {
                            case 0:
                                {
                                    SetCursor(Properties.Resources.line, hotP);
                                    break;
                                }
                            case 1:
                                {
                                    SetCursor(Properties.Resources.rect, hotP);
                                    break;
                                }
                            case 2:
                                {
                                    SetCursor(Properties.Resources.circle, hotP);
                                    break;
                                }
                        }
                    }
                    else if (keyData == Keys.Escape && fullscreen)
                    {
                        SetFullScreen(false, ref rect);
                        UnhookWindowsHookEx(hKeyboardHook);
                        Application.Exit();
                    }
                    else if (keyData == Keys.C && Control.ModifierKeys == Keys.Control && !IsOnDrawing && fullscreen)
                    {
                        FigureList.RemoveAt(FigureList.Count - 1);
                        index--;
                        this.Refresh();
                    }
                    else if (keyData == Keys.A && Control.ModifierKeys == Keys.Control && !IsOnDrawing && fullscreen)
                    {
                        FigureList.Clear();
                        index = -1;
                        this.Refresh();
                    }
                    else if (keyData == Keys.End && fullscreen && !IsOnDrawing)
                    {
                        textBox1.Show();
                    }
                    textBox1.Text += keyData.ToString()+"\r\n";
                }
            }
                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
        }
#endregion

#region 作图
        Graphics g;
        Image img;
        int DrawingMode = 0;
        
        private void RefreshScreenPic()
        {
            img = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            g = Graphics.FromImage(img);
            g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
            this.BackgroundImage = img;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //install hook
            SetCursor(Properties.Resources.line, hotP);
            this.DoubleBuffered = true;
            RefreshScreenPic();
            InitHook();
            FullScreen();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            SetFullScreen(false, ref rect);
            UnhookWindowsHookEx(hKeyboardHook);
        }

        List<FigureEx> FigureList = new List<FigureEx>();
        bool IsOnDrawing = false;
        int index = -1;
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            foreach (FigureEx fe in FigureList)
            {
                if (fe is Line)
                    e.Graphics.DrawLine(new Pen(fe.FColor, 3), fe.StartPoint, fe.EndPoint);
                else if (fe is Rect)
                    e.Graphics.DrawRectangle(new Pen(fe.FColor, 3), new Rectangle(fe.StartPoint.X, fe.StartPoint.Y, fe.EndPoint.X - fe.StartPoint.X, fe.EndPoint.Y - fe.StartPoint.Y));
                else if (fe is Circle)
                    e.Graphics.DrawEllipse(new Pen(fe.FColor, 3), new Rectangle(fe.StartPoint.X, fe.StartPoint.Y, fe.EndPoint.X - fe.StartPoint.X, fe.EndPoint.Y - fe.StartPoint.Y));
            }
            //由于钩子会突然消失，所以随时重建钩子
            UnhookWindowsHookEx(hKeyboardHook);
            InitHook();
            //
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            IsOnDrawing = true;
            FigureEx fe;
            switch (DrawingMode)
            {
                case 0:
                    {
                        fe = new Line();
                        break;
                    }
                case 1:
                    {
                        fe = new Rect();
                        break;
                    }
                case 2:
                    {
                        fe = new Circle();
                        break;
                    }
                default: 
                    {
                        fe = new Line();
                        break;
                    }
            }
            fe.StartPoint = e.Location;
            fe.EndPoint = e.Location;
            FigureList.Add(fe);
            index++;
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            IsOnDrawing = false;
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsOnDrawing)
            {
                FigureList[index].EndPoint = e.Location;
                this.Refresh();
            }
        }
#endregion

#region 设置鼠标样式
        //8X26
        private Point hotP = new Point(8, 24);
        public void SetCursor(Bitmap cursor, Point hotPoint)
        {
            int hotX = hotPoint.X;
            int hotY = hotPoint.Y;
            Bitmap myNewCursor = new Bitmap(cursor.Width * 2, cursor.Height * 2);
            Graphics g = Graphics.FromImage(myNewCursor);
            g.Clear(Color.FromArgb(0, 0, 0, 0));
            g.DrawImage(cursor, cursor.Width - hotX, cursor.Height - hotY, cursor.Width,
            cursor.Height);

            this.Cursor = new Cursor(myNewCursor.GetHicon());

            g.Dispose();
            myNewCursor.Dispose();
        }
#endregion
    }
     
}
